package com.xiaodu.rest.config;

import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

import java.util.concurrent.TimeUnit;

/**
 * @author: dutianjie
 * @date: 2021/4/13
 * @version: v1.0.0
 * @description: 描述
 **/
@Configuration
@ConditionalOnClass(RestTemplate.class)
public class RestTemplateConfig {

    @Bean
    @Primary
    public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) {
//        return restTemplateBuilder/*.setReadTimeout(Duration.ofSeconds(5)).setConnectTimeout(Duration.ofSeconds(2))*/.build();
        return restTemplateBuilder.additionalInterceptors(new LogClientHttpRequestInterceptor()).build();
    }

    @Bean
    public RestTemplate restTemplateOkHttpClient(RestTemplateBuilder restTemplateBuilder) {
        return restTemplateBuilder/*.setReadTimeout(Duration.ofSeconds(5)).setConnectTimeout(Duration.ofSeconds(2))*/.build();
    }

    @Configuration
    @ConditionalOnClass(HttpClient.class)
    @EnableConfigurationProperties(HttpClientProperties.class)
    public static class HttpClientConfig {

        @Autowired
        private HttpClientProperties httpClientProperties;

        // 配置 httpClient
        @Bean
        public HttpClient httpClient() {
            HttpClientBuilder customHttpClient = HttpClients.custom();
            RequestConfig.Builder customRequestConfig = RequestConfig.custom();
            customRequestConfig.setConnectionRequestTimeout(httpClientProperties.getConnectionTimeout().intValue()) // 获取连接超时时间
                    .setSocketTimeout(httpClientProperties.getReadTimeout().intValue()) //
                    .setConnectTimeout(2000); // 建立连接超时时间
            customHttpClient.setConnectionManager(httpClientConnectionManager())
                    .setDefaultRequestConfig(customRequestConfig.build())
                    .evictIdleConnections(httpClientProperties.getMaxIdleTime(), TimeUnit.SECONDS) // 连接空闲时间，超时驱逐
                    .disableAutomaticRetries(); // 禁止自动重试

            return customHttpClient.build();
        }

        // 配置 httpClientConnectionManager 连接请求管理者
        @Bean
        public HttpClientConnectionManager httpClientConnectionManager() {
            PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager();
            poolingHttpClientConnectionManager.setMaxTotal(httpClientProperties.getMaxConnectionTotal()); // 池中最大连接总数
            int defMaxPerRoute = httpClientProperties.getMaxConnectionTotal() / 10;
            if (defMaxPerRoute <= 0) defMaxPerRoute = 1;
            poolingHttpClientConnectionManager.setDefaultMaxPerRoute(defMaxPerRoute); // 最大路由
            return poolingHttpClientConnectionManager;
        }

        // 配置 httpRequestFactory 这个是spring提供的
        @Bean
        public HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory(HttpClient httpClient, RestTemplate restTemplate) {
            HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
            restTemplate.setRequestFactory(httpComponentsClientHttpRequestFactory);
            return httpComponentsClientHttpRequestFactory;
        }

    }

    @Configuration
    @ConditionalOnClass(OkHttpClient.class)
    public static class OkHttpClientConfig {

        @Bean
        public OkHttpClient okHttpClient() {
            OkHttpClient.Builder okHttpClient = new OkHttpClient.Builder();
            return okHttpClient.build();
        }

        @Bean
        public OkHttp3ClientHttpRequestFactory okHttp3ClientHttpRequestFactory(@Qualifier("restTemplateOkHttpClient") RestTemplate restTemplateOkHttpClient) {
            OkHttp3ClientHttpRequestFactory okHttp3ClientHttpRequestFactory = new OkHttp3ClientHttpRequestFactory();
            restTemplateOkHttpClient.setRequestFactory(okHttp3ClientHttpRequestFactory);
            okHttp3ClientHttpRequestFactory.setWriteTimeout(15000);
            okHttp3ClientHttpRequestFactory.setConnectTimeout(3000);
            okHttp3ClientHttpRequestFactory.setReadTimeout(15000);
            return okHttp3ClientHttpRequestFactory;
        }
    }
}
